package com.gmlive.common.ui.dialog;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import com.gmlive.common.ui.R;
import com.gmlive.common.ui.dialog.detachable.DetachableOnClickListener;
import com.gmlive.common.ui.util.DisplayHelper;
import com.gmlive.common.ui.util.ResHelper;
import com.gmlive.common.ui.widget.LineSpaceExtraTextView;

import java.lang.ref.WeakReference;

import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;

/**
 * @Author: 姜志敏
 * @CreateDate: 2019-07-08 19:28
 */
class AlertController {
    private static final int BUTTON_STYLE_LEFT = 0;
    private static final int BUTTON_STYLE_RIGHT = 1;
    private static final int BUTTON_STYLE_SINGLE = 2;

    private final Context mContext;
    private final Dialog mDialog;
    private final Window mWindow;

    private int mAlertDialogLayout;

    private int mThemeColor;
    private int mTitleColor;
    private int mMessageColor;
    private int mMessageNoTitleColor;
    private int mBackgroundColor;
    private int mDividerColor;
    private int mButtonPressColor;
    private int mButtonTextColor;

    private CharSequence mTitle;
    private CharSequence mMessage;
    private int mMessageGravity = -1;
    private CharSequence mLink;

    private TextView mTitleView;
    private LineSpaceExtraTextView mMessageView;
    private TextView mLinkView;

    private Message mLinkMessage;
    private boolean mDimissOnLinkClick;

    private View mView;
    private int mViewLayoutResId;

    private Button mButtonNegative;
    private CharSequence mButtonNegativeText;
    private Message mButtonNegativeMessage;
    private boolean mDismissOnNegativeClick;

    private Button mButtonPositive;
    private CharSequence mButtonPositiveText;
    private Message mButtonPositiveMessage;
    private boolean mDismissOnPositiveClick;

    private boolean useFullWidth;

    private Handler mHandler;

    private final View.OnClickListener mButtonHandler = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            final Message m;
            final boolean dismissOnClick;
            if (v == mButtonPositive && mButtonPositiveMessage != null) {
                m = Message.obtain(mButtonPositiveMessage);
                dismissOnClick = mDismissOnPositiveClick;
            } else if (v == mButtonNegative && mButtonNegativeMessage != null) {
                m = Message.obtain(mButtonNegativeMessage);
                dismissOnClick = mDismissOnNegativeClick;
            } else if (v == mLinkView && mLinkMessage != null) {
                m = Message.obtain(mLinkMessage);
                dismissOnClick = mDimissOnLinkClick;
            } else {
                m = null;
                dismissOnClick = true;
            }

            if (m != null) {
                m.sendToTarget();
            }

            // Post a message so we dismiss after the above handlers are executed
            if (dismissOnClick) {
                mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialog)
                        .sendToTarget();
            }
        }
    };

    public AlertController(Context context, Dialog di, Window window) {
        mContext = context;
        mDialog = di;
        mWindow = window;
        mHandler = new ButtonHandler(di);

        mAlertDialogLayout = R.layout.ik_alert_dialog;
        mThemeColor = ResHelper.getThemeColor(context);
    }

    void setStyleColors(int themeColor, int titleColor, int messageColor, int messageNoTitleColor,
                        int backgroundColor, int dividerColor, int buttonPressColor, int buttonTextColor) {
        mThemeColor = themeColor;
        mTitleColor = titleColor;
        mMessageColor = messageColor;
        mMessageNoTitleColor = messageNoTitleColor;
        mBackgroundColor = backgroundColor;
        mDividerColor = dividerColor;
        mButtonPressColor = buttonPressColor;
        mButtonTextColor = buttonTextColor;
    }

    public void setTitle(CharSequence title) {
        mTitle = title;
        if (mTitleView != null) {
            mTitleView.setText(title);
        }
    }

    public void setUseFullWidth(boolean useFullWidth) {
        this.useFullWidth = useFullWidth;
    }

    public void setMessage(CharSequence message) {
        mMessage = message;
        if (mMessageView != null) {
            mMessageView.setUseFullWidthText(message, useFullWidth);
        }
    }

    public void setMessage(CharSequence message, int gravity) {
        mMessage = message;
        mMessageGravity = gravity;
        if (mMessageView != null) {
            mMessageView.setUseFullWidthText(message, useFullWidth);
        }
    }

    public void setLink(CharSequence link, boolean autoDismiss, DialogInterface.OnClickListener listener) {
        DetachableOnClickListener linkListener = new DetachableOnClickListener(listener);
        linkListener.clearOnDetach(mDialog);

        mLink = link;
        mLinkMessage = mHandler.obtainMessage(ButtonHandler.BUTTON_LINK, linkListener);
        if (mLinkView != null) {
            mLinkView.setText(link);
        }
        mDimissOnLinkClick = autoDismiss;
    }

    public void setView(int layoutResId) {
        mView = null;
        mViewLayoutResId = layoutResId;
    }

    public void setView(View view) {
        mView = view;
        mViewLayoutResId = 0;
    }

    public void setButton(int whichButton, CharSequence text, boolean autoDismiss,
                          DialogInterface.OnClickListener listener, Message msg) {
        DetachableOnClickListener clickListener = new DetachableOnClickListener(listener);
        clickListener.clearOnDetach(mDialog);

        if (msg == null && listener != null) {
            msg = mHandler.obtainMessage(whichButton, clickListener);
        }

        switch (whichButton) {
            case DialogInterface.BUTTON_POSITIVE:
                mButtonPositiveText = text;
                mButtonPositiveMessage = msg;
                mDismissOnPositiveClick = autoDismiss;
                break;
            case DialogInterface.BUTTON_NEGATIVE:
                mButtonNegativeText = text;
                mButtonNegativeMessage = msg;
                mDismissOnNegativeClick = autoDismiss;
                break;
            default:
                throw new IllegalArgumentException("Button does not exist");
        }
    }

    public Button getButton(int whichButton) {
        switch (whichButton) {
            case DialogInterface.BUTTON_POSITIVE:
                return mButtonPositive;
            case DialogInterface.BUTTON_NEGATIVE:
                return mButtonNegative;
            default:
                return null;
        }
    }

    public int getThemeColor() {
        return mThemeColor;
    }

    private static boolean canTextInput(View v) {
        if (v.onCheckIsTextEditor()) {
            return true;
        }

        if (!(v instanceof ViewGroup)) {
            return false;
        }

        ViewGroup vg = (ViewGroup) v;
        int i = vg.getChildCount();
        while (i > 0) {
            i--;
            v = vg.getChildAt(i);
            if (canTextInput(v)) {
                return true;
            }
        }

        return false;
    }

    public void installContent() {
        mDialog.setContentView(mAlertDialogLayout);
        setupView();
    }

    private void setupView() {
        final ViewGroup parentPanel = mWindow.findViewById(R.id.parentPanel);
        Drawable drawable = ResHelper.createRoundButtonBackground(mContext, mBackgroundColor, DisplayHelper.dpToPx(15), true);
        mWindow.setBackgroundDrawable(drawable);
        final ViewGroup customPanel = parentPanel.findViewById(R.id.customPanel);
        final ViewGroup contentPanel = parentPanel.findViewById(R.id.contentPanel);
        final ViewGroup buttonPanel = parentPanel.findViewById(R.id.buttonPanel);

        setupCustomContent(customPanel);

        setupContent(contentPanel);
        setupButtons(buttonPanel);
        setupTitle();
    }

    private void setupTitle() {
        final boolean hasTextTitle = !TextUtils.isEmpty(mTitle);
        if (hasTextTitle) {
            mTitleView = mWindow.findViewById(R.id.tv_title);
            mTitleView.setText(mTitle);
            mTitleView.setTextColor(mTitleColor);
        } else {
            mWindow.findViewById(R.id.tv_title).setVisibility(View.GONE);
        }
    }

    private void setupContent(ViewGroup contentPanel) {
        ScrollView scrollView = mWindow.findViewById(R.id.scrollView);
        scrollView.setFocusable(false);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            scrollView.setNestedScrollingEnabled(false);
        }

        mMessageView = contentPanel.findViewById(R.id.tv_message);
        if (mMessage != null && mMessageView != null) {
            mMessageView.setUseFullWidthText(mMessage, useFullWidth);

            View messageSpaceTop = contentPanel.findViewById(R.id.message_space_top);
            View messageSpaceBottom = contentPanel.findViewById(R.id.message_space_bottom);

            final boolean hasTitle = !TextUtils.isEmpty(mTitle);
            if (hasTitle) {
                mMessageView.setTextColor(mMessageColor);
                LinearLayout.LayoutParams topLp = (LinearLayout.LayoutParams) messageSpaceTop.getLayoutParams();
                topLp.height = mContext.getResources().getDimensionPixelSize(R.dimen.ik_alert_dialog_message_margin_top);
                messageSpaceTop.setLayoutParams(topLp);

                LinearLayout.LayoutParams bottomLp = (LinearLayout.LayoutParams) messageSpaceBottom.getLayoutParams();
                bottomLp.height = mContext.getResources().getDimensionPixelSize(R.dimen.ik_alert_dialog_message_margin_bottom);
                messageSpaceBottom.setLayoutParams(bottomLp);
            } else {
                mMessageView.setTextColor(mMessageNoTitleColor);
                LinearLayout.LayoutParams topLp = (LinearLayout.LayoutParams) messageSpaceTop.getLayoutParams();
                topLp.height = mContext.getResources().getDimensionPixelSize(R.dimen.ik_alert_dialog_message_margin_top_no_title);
                messageSpaceTop.setLayoutParams(topLp);

                LinearLayout.LayoutParams bottomLp = (LinearLayout.LayoutParams) messageSpaceBottom.getLayoutParams();
                bottomLp.height = mContext.getResources().getDimensionPixelSize(R.dimen.ik_alert_dialog_message_margin_bottom_no_title);
                messageSpaceBottom.setLayoutParams(bottomLp);
            }

            // 默认情况下，message 一行居中，超过一行时左对其
            if (mMessageGravity == -1) {
                mMessageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        if (mMessageView.getLineCount() > 1) {
                            mMessageView.setGravity(Gravity.START);
                        } else {
                            mMessageView.setGravity(Gravity.CENTER);
                        }

                        mMessageView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    }
                });
            } else {
                mMessageView.setGravity(mMessageGravity);
            }
        } else {
            mMessageView.setVisibility(View.GONE);
            scrollView.removeView(mMessageView);
        }

        mLinkView = contentPanel.findViewById(R.id.tv_link);
        if (mLink != null) {
            mLinkView.setText(mLink);
            mLinkView.setTextColor(mThemeColor);
            mLinkView.setBackground(buildLinkBackground());
            Paint linkPaint = mLinkView.getPaint();
            linkPaint.setFlags(Paint.UNDERLINE_TEXT_FLAG);
            linkPaint.setAntiAlias(true);
            mLinkView.setOnClickListener(mButtonHandler);

            mLinkView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (mLinkView.getLineCount() > 1) {
                        mLinkView.setGravity(Gravity.START);
                    } else {
                        mLinkView.setGravity(Gravity.CENTER);
                    }

                    mLinkView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                }
            });
        } else {
            mLinkView.setVisibility(View.GONE);
        }

        if (mMessage == null && mLink == null) {
            contentPanel.setVisibility(View.GONE);
        }
    }

    private void setupCustomContent(ViewGroup customPanel) {
        final View customView;
        if (mView != null) {
            customView = mView;
        } else if (mViewLayoutResId != 0) {
            final LayoutInflater inflater = LayoutInflater.from(mContext);
            customView = inflater.inflate(mViewLayoutResId, customPanel, false);
        } else {
            customView = null;
        }

        final boolean hasCustomView = customView != null;
        if (!hasCustomView || !canTextInput(customView)) {
            mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        }

        if (hasCustomView) {
            final FrameLayout custom = mWindow.findViewById(R.id.custom);
            custom.addView(customView, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        } else {
            customPanel.setVisibility(View.GONE);
        }
    }

    private void setupButtons(ViewGroup buttonPanel) {
        int BIT_BUTTON_POSITIVE = 1;
        int BIT_BUTTON_NEGATIVE = 2;
        int whichButtons = 0;

        mButtonPositive = buttonPanel.findViewById(R.id.button2);
        mButtonPositive.setOnClickListener(mButtonHandler);

        if (TextUtils.isEmpty(mButtonPositiveText)) {
            mButtonPositive.setVisibility(View.GONE);
        } else {
            mButtonPositive.setVisibility(View.VISIBLE);
            mButtonPositive.setText(mButtonPositiveText);
            whichButtons |= BIT_BUTTON_POSITIVE;
        }

        mButtonNegative = buttonPanel.findViewById(R.id.button1);
        mButtonNegative.setOnClickListener(mButtonHandler);

        if (TextUtils.isEmpty(mButtonNegativeText)) {
            mButtonNegative.setVisibility(View.GONE);
        } else {
            mButtonNegative.setVisibility(View.VISIBLE);
            mButtonNegative.setText(mButtonNegativeText);
            whichButtons |= BIT_BUTTON_NEGATIVE;
        }

        boolean hasButtons = whichButtons != 0;
        if (!hasButtons) {
            buttonPanel.setVisibility(View.GONE);
        } else {
            buttonPanel.setBackground(createButtonPanelBackground());
            // 设置按钮背景和字体颜色
            if (whichButtons < 3) {
                // 只有一个按钮
                Button button = whichButtons == BIT_BUTTON_POSITIVE ? mButtonPositive : mButtonNegative;
                button.setTextColor(mThemeColor);
                button.setBackground(createButtonBackground(BUTTON_STYLE_SINGLE));
            } else {
                // 设置分割线颜色
                View divider = buttonPanel.findViewById(R.id.button_divider);
                divider.setBackgroundColor(mDividerColor);

                mButtonPositive.setTextColor(mThemeColor);
                mButtonPositive.setBackground(createButtonBackground(BUTTON_STYLE_RIGHT));

                mButtonNegative.setTextColor(mButtonTextColor);
                mButtonNegative.setBackground(createButtonBackground(BUTTON_STYLE_LEFT));
            }
        }
    }

    private StateListDrawable buildLinkBackground() {
        GradientDrawable pressedDrawable = new GradientDrawable();
        pressedDrawable.setAlpha(52); // 20%不透明
        pressedDrawable.setColor(mThemeColor);
        GradientDrawable normalDrawable = new GradientDrawable();
        normalDrawable.setAlpha(0);

        StateListDrawable stateListDrawable = new StateListDrawable();
        stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedDrawable);
        stateListDrawable.addState(new int[]{}, normalDrawable);

        return stateListDrawable;
    }

    private StateListDrawable createButtonBackground(int buttonStyle) {
        float[] radii = new float[8];
        int radius = DisplayHelper.dpToPx(15);
        if (buttonStyle == BUTTON_STYLE_LEFT) {
            radii[0] = 0; // top-left
            radii[1] = 0;
            radii[2] = 0; // top-right
            radii[3] = 0;
            radii[4] = 0; // bottom-right
            radii[5] = 0;
            radii[6] = radius; // bottom-left
            radii[7] = radius;
        } else if (buttonStyle == BUTTON_STYLE_RIGHT) {
            radii[0] = 0; // top-left
            radii[1] = 0;
            radii[2] = 0; // top-right
            radii[3] = 0;
            radii[4] = radius; // bottom-right
            radii[5] = radius;
            radii[6] = 0; // bottom-left
            radii[7] = 0;
        } else {
            // BUTTON_STYLE_SINGLE
            radii[0] = 0; // top-left
            radii[1] = 0;
            radii[2] = 0; // top-right
            radii[3] = 0;
            radii[4] = radius; // bottom-right
            radii[5] = radius;
            radii[6] = radius; // bottom-left
            radii[7] = radius;
        }

        GradientDrawable pressedDrawable = new GradientDrawable();
        pressedDrawable.setCornerRadii(radii);
        pressedDrawable.setColor(mButtonPressColor);
        GradientDrawable normalDrawable = new GradientDrawable();
        normalDrawable.setCornerRadii(radii);
        normalDrawable.setColor(Color.TRANSPARENT);

        StateListDrawable stateListDrawable = new StateListDrawable();
        stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedDrawable);
        stateListDrawable.addState(new int[]{}, normalDrawable);

        return stateListDrawable;
    }

    private Drawable createButtonPanelBackground() {
        float[] radii = new float[8];
        int radius = DisplayHelper.dpToPx(15);
        radii[0] = 0; // top-left
        radii[1] = 0;
        radii[2] = 0; // top-right
        radii[3] = 0;
        radii[4] = radius; // bottom-right
        radii[5] = radius;
        radii[6] = radius; // bottom-left
        radii[7] = radius;

        return ResHelper.createSeparatorDrawable(mBackgroundColor, mDividerColor, 2, radii);
    }

    private static final class ButtonHandler extends Handler {
        // Button clicks have Message.what as the BUTTON{1,2,3} constant
        private static final int MSG_DISMISS_DIALOG = 1;

        private static final int BUTTON_LINK = -4;

        private WeakReference<DialogInterface> mDialog;

        public ButtonHandler(DialogInterface dialog) {
            mDialog = new WeakReference<>(dialog);
        }

        @Override
        public void handleMessage(Message msg) {
            try {
                switch (msg.what) {
                    case DialogInterface.BUTTON_POSITIVE:
                    case DialogInterface.BUTTON_NEGATIVE:
                    case DialogInterface.BUTTON_NEUTRAL:
                    case BUTTON_LINK:
                        ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
                        break;

                    case MSG_DISMISS_DIALOG:
                        ((DialogInterface) msg.obj).dismiss();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static class AlertParams {
        public final Context mContext;
        public final LayoutInflater mInflater;

        public CharSequence mTitle;
        public CharSequence mMessage;
        public int mGravity = -1;

        public CharSequence mPositiveButtonText;
        public DialogInterface.OnClickListener mPositiveButtonListener;
        public boolean mPositiveAutoDismiss;

        public CharSequence mNegativeButtonText;
        public DialogInterface.OnClickListener mNegativeButtonListener;
        public boolean mNegativeAutoDismiss;

        public CharSequence mLink;
        public DialogInterface.OnClickListener mLinkListener;
        public boolean mLinkAutoDismiss;

        public boolean mCancelable;
        public DialogInterface.OnCancelListener mOnCancelListener;
        public DialogInterface.OnDismissListener mOnDismissListener;
        public DialogInterface.OnKeyListener mOnKeyListener;
        public boolean useFullWidth;
        public View mView;
        public int mViewLayoutResId = 0;

        public AlertParams(Context context) {
            mContext = context;
            mCancelable = true;
            mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

        public void apply(AlertController dialog) {
            // TO-DO add custom title
            if (mTitle != null) {
                dialog.setTitle(mTitle);
            }

            dialog.setUseFullWidth(useFullWidth);

            if (mMessage != null) {
                dialog.setMessage(mMessage, mGravity);
            }

            if (mLink != null) {
                dialog.setLink(mLink, mLinkAutoDismiss, mLinkListener);
            }

            if (mPositiveButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
                        mPositiveAutoDismiss, mPositiveButtonListener, null);
            }

            if (mNegativeButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
                        mNegativeAutoDismiss, mNegativeButtonListener, null);
            }

            if (mView != null) {
                dialog.setView(mView);
            } else if (mViewLayoutResId != 0) {
                dialog.setView(mViewLayoutResId);
            }
        }
    }
}
